/**********************************************************************

  Audacity: A Digital Audio Editor

  ExportPlugin.h

  Dominic Mazzoni

**********************************************************************/
#pragma once

#include <memory>

// #include <rapidjson/fwd.h>

#include <wx/string.h>

#include "ExportOptionsEditor.h"
#include "wxArrayStringEx.h"
#include "Identifier.h"
#include "TranslatableString.h"
#include "wxFileNameWrapper.h"

class wxFileName;
class wxString;

class AudacityProject;
class Tags;

namespace MixerOptions {
class Downmix;
}

struct IMPORT_EXPORT_API FormatInfo final
{
    wxString format;
    TranslatableString description;
    FileExtensions extensions;
    unsigned maxChannels;
    bool canMetaData;
};

class IMPORT_EXPORT_API ExportException
{
    const wxString mMessage;
public:

    ExportException(const wxString& msg);

    const wxString& What() const noexcept;
};

class IMPORT_EXPORT_API ExportErrorException
{
    TranslatableString mMessage;
    wxString mHelpPageId;
public:
    /// We have many Export errors that are essentially anonymous
    /// and are distinguished only by an error code number.
    /// Rather than repeat the code, we have it just once.
    ExportErrorException(const wxString& errorCode);
    //
    ExportErrorException(TranslatableString message, const wxString& helpPage);

    const TranslatableString& GetMessage() const noexcept;
    const wxString& GetHelpPageId() const noexcept;
};

class IMPORT_EXPORT_API ExportDiskFullError
{
    wxFileNameWrapper mFileName;
public:
    ExportDiskFullError(const wxFileNameWrapper& fileName);

    const wxFileNameWrapper& GetFileName() const noexcept;
};

class IMPORT_EXPORT_API ExportProcessorDelegate
{
public:
    virtual ~ExportProcessorDelegate();

    virtual bool IsCancelled() const = 0;
    virtual bool IsStopped() const = 0;
    virtual void SetStatusString(const TranslatableString& str) = 0;
    virtual void OnProgress(double progress) = 0;
};

class IMPORT_EXPORT_API ExportProcessor
{
public:
    using Parameters = std::vector<std::tuple<ExportOptionID, ExportValue> >;

    ExportProcessor(const ExportProcessor&) = delete;
    ExportProcessor& operator=(const ExportProcessor&) = delete;

    ExportProcessor() = default;
    virtual ~ExportProcessor();

    /**
     * @brief Called before start processing.
     *
     * @param project Processor may access project data, take care to exclude any data race
     * @param parameters A format-dependent set of parameters used in exporting
     * @param selectedOnly Set to true if all tracks should be mixed, to false
     * if only the selected tracks should be mixed and exported.
     * @param tags A Tags object that will over-ride the one in *project and
     * be used to tag the file that is exported.
     * @retern Implementations may simply return false without any error reporting.
     * This is to temporarily preserve old behavior, which is to be removed in the
     * nearest future.
     */
    virtual bool Initialize(AudacityProject& project, const Parameters& parameters, const wxFileNameWrapper& filename, double t0, double t1,
                            bool selectedOnly, double rate, unsigned channels, MixerOptions::Downmix* mixerSpec = nullptr,
                            const Tags* tags = nullptr) = 0;

    virtual ExportResult Process(ExportProcessorDelegate& delegate) = 0;
};

//----------------------------------------------------------------------------
// ExportPlugin
//----------------------------------------------------------------------------
class IMPORT_EXPORT_API ExportPlugin /* not final */
{
public:

    ExportPlugin();
    virtual ~ExportPlugin();

    virtual int GetFormatCount() const = 0;
    /**
     * \brief Returns FormatInfo structure for given index if it's valid,
     * or a default one.
     * FormatInfo::format isn't guaranteed to be unique.
     * \param index Should not exceed the number of formats
     * provided by GetFormatCount()
     */
    virtual FormatInfo GetFormatInfo(int index) const = 0;

    /**
     * @brief Creates format-dependent options editor, that is used to create
     * a valid set of parameters to be used in exporting.
     *
     * @param listener Option listener object that could be used by the editor
     * to report on option changes.
     */
    virtual std::unique_ptr<ExportOptionsEditor>
    CreateOptionsEditor(int formatIndex, ExportOptionsEditor::Listener* listener) const = 0;

    /// \return Mime type(s) supported by the format.
    virtual std::vector<std::string> GetMimeTypes(int formatIndex) const;

    /**
     * @brief Attempt to parse configuration JSON object and produce
     * a suitable set of parameters. Configuration is format dependent.
     *
     * @param formatIndex Internal format index
     * @param config Configuration JSON object
     * @param parameters Where to put parameters
     * @return Whether the parsing was successful
     **/
    // virtual bool ParseConfig(int formatIndex, const rapidjson::Value& config, ExportProcessor::Parameters& parameters) const;

    virtual bool CheckFileName(wxFileName& filename, int format = 0) const;

    /**
     * @param format Control which of the multiple formats this exporter is
     * capable of exporting should be used. Used where a single export plug-in
     * handles a number of related formats, but they have separate
     * entries in the Format drop-down list box. For example, the options to
     * export to "Other PCM", "AIFF 16 Bit" and "WAV 16 Bit" are all the same
     * libsndfile export plug-in, but with subformat set to 0, 1, and 2
     * respectively.
     **/
    virtual std::unique_ptr<ExportProcessor> CreateProcessor(int format) const = 0;
};
